using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Drawing.Drawing2D;
using System.Diagnostics;
using System.Windows.Forms.Design;
using Mersiv.App.Client.Data;
using Mersiv.App.Client.Controller;
using Mersiv.App.Client.Logging;
using Mersiv.Lib.Wrapper;
using Mersiv.Lib.Wrapper.Command;
using Mersiv.Lib.Wrapper.Event;

namespace Mersiv.App.Client.Controls
{

	//[Designer(typeof(ParentControlDesigner))]
	public partial class RepositoryPanel : UserControl
	{

		private int _visibleCount = -1;
		private int _lastCount = -1;
		private int	_maxHeight;

    private DataModel dataModel;
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    internal DataModel DataModel
    {
      get
      { 
        return this.dataModel; 
      }
      set
      {
        if (value != null)
        {
          if (this.dataModel != null)
          {
            //
            // TODO: remove old event
            //
          }
          this.dataModel = value;
          this.dataModel.RepositoryAdded += new HgRepositoryEvent(dataModel_RepositoryAdded);
        }
      }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    internal HgCommandController HgCommandController { get; set; }


    #region Public Methods

    public void Add(HgRepositoryTreeNode dataTreeNode)
    {
      this.repositoryTreeView.Nodes.Add(dataTreeNode);
    }

    public void Add(HgRepository hgRepository)
    {
      HgRepositoryTreeNode hgRepositoryTreeNode = new HgRepositoryTreeNode();
      hgRepositoryTreeNode.Repository = hgRepository;
      this.Add(hgRepositoryTreeNode);
    }

    public HgRepository SelectedRepository
    {
      get
      {
        TreeNode treeNode = this.repositoryTreeView.SelectedNode;
        if (treeNode != null)
        {
          try
          {
            HgRepositoryTreeNode hgRepositoryTreeNode = (HgRepositoryTreeNode)treeNode;
            return hgRepositoryTreeNode.Repository;
          }
          catch
          {
          }
        }
        return null;
      }
    }

    public void Remove(HgRepository hgRepository)
    {
      foreach (TreeNode treeNode in this.repositoryTreeView.Nodes)
      {
        try
        {
          HgRepositoryTreeNode hgRepositoryTreeNode = (HgRepositoryTreeNode)treeNode;
          if (hgRepositoryTreeNode.Repository == hgRepository)
          {
            this.repositoryTreeView.Nodes.Remove(hgRepositoryTreeNode);
          }
        }
        catch
        {
        }
      }
    }

    #endregion

    #region Setup
    public RepositoryPanel()
		{
			// Set Defaults
			this.Dock = DockStyle.Fill;
			this.TabStop = false;

			// Initialize
			InitializeComponent();

		}

		private void StackBar_Load(object sender, EventArgs e)
		{
			// Setup
			this.ssStackStrip.ItemHeightChanged += new EventHandler(stackStrip1_ItemHeightChanged);

			// Add Overflow items
			AddOverflowItems();

			// Set Height
			InitializeSplitter();

			// Set parent padding
			this.Parent.Padding = new Padding(3, 3, 0, 3);
		}

		private void AddOverflowItems()
		{
			ToolStripButton item;
			Color			trans = Color.FromArgb(238,238,238);
			string			name;

			// Add items to overflow
			for (int idx = this.ssStackStrip.ItemCount - 1; idx >= 0; idx--)
			{
				name = this.ssStackStrip.Items[idx].Tag as string;

				if (null != name)
				{
					item = new ToolStripButton(GetBitmapResource(name));
					item.ImageTransparentColor = trans;
					item.Alignment = ToolStripItemAlignment.Right;
					item.Name = name;

					this.bbsOverflowStrip.Items.Add(item);
				}
			}
		}

		private Bitmap GetBitmapResource(string name)
		{
			return Properties.Resources.ResourceManager.GetObject(name) as Bitmap;
		}
		#endregion

		#region UI Event Handlers
		private void splitContainer1_Paint(object sender, PaintEventArgs e)
		{
			ProfessionalColorTable	pct = new ProfessionalColorTable();
			Rectangle				bounds = (sender as SplitContainer).SplitterRectangle;

			int			squares;
			int			maxSquares = 9;
			int			squareSize = 4;
			int			boxSize = 2;

			// Make sure we need to do work
			if ((bounds.Width > 0) && (bounds.Height > 0))
			{
				Graphics	g = e.Graphics;

				// Setup colors from the provided renderer
				Color		begin = pct.OverflowButtonGradientMiddle;
				Color		end = pct.OverflowButtonGradientEnd;

				// Make sure we need to do work
				using (Brush b = new LinearGradientBrush(bounds, begin, end, LinearGradientMode.Vertical))
				{
					g.FillRectangle(b, bounds);
				}

				// Calculate squares
				if ((bounds.Width > squareSize) && (bounds.Height > squareSize))
				{
					squares = Math.Min((bounds.Width / squareSize), maxSquares);

					// Calculate start
					int		start = (bounds.Width - (squares * squareSize)) / 2;
					int		Y = bounds.Y  + 1;

					// Get brushes
					Brush dark = new SolidBrush(pct.GripDark);
					Brush middle = new SolidBrush(pct.ToolStripBorder);
					Brush light = new SolidBrush(pct.ToolStripDropDownBackground);

					// Draw
					for (int idx = 0; idx < squares; idx++)
					{
						// Draw grips
						g.FillRectangle(dark, start, Y, boxSize, boxSize);
						g.FillRectangle(light, start + 1, Y+1, boxSize, boxSize);
						g.FillRectangle(middle, start + 1, Y+1, 1, 1);
						start += squareSize;
					}

					dark.Dispose();
					middle.Dispose();
					light.Dispose();
				}
			}
		}

		void stackStrip1_ItemHeightChanged(object sender, EventArgs e)
		{
			InitializeSplitter();
		}

		private void stackStripSplitter_SplitterMoved(object sender, SplitterEventArgs e)
		{
			if ((_maxHeight > 0) && ((this.stackStripSplitContainer.Height - e.SplitY) > _maxHeight))
			{
				// Limit to max height
				this.stackStripSplitContainer.SplitterDistance = this.stackStripSplitContainer.Height - _maxHeight;

				// Set to max
				_visibleCount = this.ssStackStrip.ItemCount;
			}
			else if ((_visibleCount > 0) && (this.ssStackStrip.ItemCount > 0))
			{
				// Make sure overflow is correct
				_visibleCount = (this.ssStackStrip.Height / this.ssStackStrip.ItemHeight);

				// See if this changed
				if (_lastCount != _visibleCount)
				{
					int		count = this.bbsOverflowStrip.Items.Count;

					// Update overflow items
					for (int idx = 1; idx < count; idx++)
					{
						this.bbsOverflowStrip.Items[idx].Visible = (idx < (count - _visibleCount));
					}

					// Update last
					_lastCount = _visibleCount;
				}
			}
		}
		#endregion

		#region Private API
		private void InitializeSplitter()
		{
			// Set slider increment
			if (this.ssStackStrip.ItemHeight > 0)
			{
				this.stackStripSplitContainer.SplitterIncrement = this.ssStackStrip.ItemHeight;

				// Find visible count
				if (_visibleCount < 0)
				{
					_visibleCount = this.ssStackStrip.InitialDisplayCount;
				}

				// Setup BaseStackStrip
				this.bbsOverflowStrip.Height = this.ssStackStrip.ItemHeight;

				// Set splitter distance
				int min = this.ssStackStrip.ItemHeight + this.bbsOverflowStrip.Height;
				int distance = this.stackStripSplitContainer.Height - this.stackStripSplitContainer.SplitterWidth - ((_visibleCount * this.ssStackStrip.ItemHeight) + this.bbsOverflowStrip.Height);

				// Set Max
				_maxHeight = (this.ssStackStrip.ItemHeight * this.ssStackStrip.ItemCount) + this.bbsOverflowStrip.Height + this.stackStripSplitContainer.SplitterWidth;

				// In case it's sized too small on startup
				if (distance < 0)
				{
					distance = min;
				}

				// Set Min/Max
				this.stackStripSplitContainer.SplitterDistance = distance;
				this.stackStripSplitContainer.Panel1MinSize = min;
			}
		}
    #endregion

    private void RemoveLocalRepository()
    {
      if (this.DataModel != null)
      {
        HgRepository hgRepository = this.SelectedRepository;
        if (hgRepository != null)
        {
          this.Remove(hgRepository);
          this.dataModel.Remove(hgRepository);
        }
        else
        {
          MessageBox.Show(this, "Please select a repository from the list");
        }
      }
      else
      {
        // TODO: create logging infrastructure
        MessageBox.Show(this, "DataModel NULL!");
      }
    }


    private void AddLocalRepository()
    {
      if (this.DataModel != null)
      {
        AddRepositoryForm addRepositoryForm = new AddRepositoryForm();
        if (DialogResult.OK == addRepositoryForm.ShowDialog(this))
        {
          HgRepository hgRepository = addRepositoryForm.Repository;
          if (this.DataModel.NotContains(hgRepository))
          {
            //Properties.Settings.Default.Upgrade();
            //Properties.Settings.Default.Reload();
            this.DataModel.Add(hgRepository);
            Properties.Settings.Default.PreviousRepositoryPath = hgRepository.WorkingDirectory;
            Properties.Settings.Default.Save();
          }
          else
          {
            //TODO: Better notification mechanism?
            MessageBox.Show(
              this,
              hgRepository.WorkingDirectory + " already added. Please choose a different repository.",
              "Error",
              MessageBoxButtons.OK,
              MessageBoxIcon.Error);
            this.AddLocalRepository();
          }
        }
      }
      else
      {
        // TODO: create logging infrastructure
        MessageBox.Show(this, "DataModel NULL!");
      }
    }

    #region Event Handlers

    private void tsbAddRepository_Click(object sender, EventArgs e)
    {
      this.AddLocalRepository();
    }

    private void tsbRemoveRepository_Click(object sender, EventArgs e)
    {
      //TODO: event
      this.RemoveLocalRepository();
    }

    private void tsbRepositoryStatus_Click(object sender, EventArgs e)
    {
      HgRepository hgRepository = this.SelectedRepository;
      if (hgRepository != null)
      {
        if (this.HgCommandController != null)
        {
          this.HgCommandController.HgStatusCommand(hgRepository);
        }
      }
      else
      {
        MessageBox.Show(this, "Please select a repository from the list");
      }
    }

    private void dataModel_RepositoryAdded(HgRepository hgRepository)
    {
      this.Add(hgRepository);
    }

    private void repositoryTreeView_AfterSelect(object sender, TreeViewEventArgs e)
    {
      this.OnHgRepositorySelected();
    }


    public event HgRepositoryEvent HgRepositorySelected;
    private void OnHgRepositorySelected()
    {
      if (this.HgRepositorySelected != null)
      {
        HgRepository hgRepository = this.SelectedRepository;
        if (hgRepository != null)
        {
          this.HgRepositorySelected(hgRepository);
          //
          // Run Status Command
          // NOTE: Should we do this here?
          //
          //if (this.HgCommandController != null)
          //{
          //  this.HgCommandController.HgStatusCommand(hgRepository);
          //}
        }
      }
    }

    #endregion Event Handlers

  }

}